Skip to content

XML Namespace Declarations for XPath Expressions#2253

Merged
predic8 merged 20 commits into
masterfrom
xml-namespace-declarations-for-xpath-expressions
Nov 5, 2025
Merged

XML Namespace Declarations for XPath Expressions#2253
predic8 merged 20 commits into
masterfrom
xml-namespace-declarations-for-xpath-expressions

Conversation

@predic8

@predic8 predic8 commented Nov 1, 2025

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • XML namespace support for dynamic expression evaluation across interceptors
    • Request builder: xml(body) for creating XML requests
    • XPath evaluation now honors configured XML namespaces
  • Documentation

    • New XML Namespaces example with runnable samples and scripts
  • Chores

    • Hardened, XXE‑safe XML parser added for safer parsing
    • Expression framework updated to propagate XML configuration
  • Tests

    • New tests covering namespace handling and XPath/JSONPath expression behavior

@coderabbitai

coderabbitai Bot commented Nov 1, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds XML namespace configuration and parsing support, refactors expression APIs to use an Interceptor context via InterceptorAdapter, introduces a hardened XML parser and XmlConfig/Namespaces, updates many interceptors to propagate XmlConfig, and adds namespace-aware tests and examples.

Changes

Cohort / File(s) Summary
XML Configuration Infrastructure
core/src/main/java/com/predic8/membrane/core/config/xml/XmlConfig.java, core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java, core/src/main/java/com/predic8/membrane/core/interceptor/XMLSupport.java
Adds XmlConfig and Namespaces types for XML namespace configuration and a XMLSupport interface for interceptors to accept XmlConfig.
XML Parsing Utilities
core/src/main/java/com/predic8/membrane/core/util/xml/parser/XmlParser.java, core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java, core/src/main/java/com/predic8/membrane/core/util/xml/parser/XmlParseException.java
Introduces XmlParser interface, an XXE-hardened HardenedXmlParser singleton implementation, and XmlParseException.
Core Expression Refactor
core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java, core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java, core/src/main/java/com/predic8/membrane/core/lang/groovy/GroovyExchangeExpression.java, core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java
Changes expression factories/constructors to accept an Interceptor (adds InterceptorAdapter), updates template/groovy/xpath implementations to use interceptor context and to apply XmlConfig/Namespaces for XPath evaluation.
Language Interceptor Base Classes
core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java, core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractExchangeExpressionInterceptor.java, core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractSetterInterceptor.java
Adds XMLSupport to AbstractLanguageInterceptor, exposes xmlConfig accessors, switches exchange expression initialization to interceptor-based context, and improves root-cause handling in setter interceptor.
Interceptors adopting XMLSupport
core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java, core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java, core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java, core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java, core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java, core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java
These interceptors now implement XMLSupport (add xmlConfig field + accessors) and initialize expressions via InterceptorAdapter/interceptor context; IdempotencyInterceptor now extends AbstractLanguageInterceptor.
Other Interceptor Callsite Updates
core/src/main/java/com/predic8/membrane/core/interceptor/flow/ForInterceptor.java, core/src/main/java/com/predic8/membrane/core/interceptor/balancer/PolyglotSessionIdExtractor.java, core/src/main/java/com/predic8/membrane/core/interceptor/ratelimit/RateLimitInterceptor.java
Switches expression creation to use interceptor-based context (this or InterceptorAdapter) instead of Router.
Request Builder
core/src/main/java/com/predic8/membrane/core/http/Request.java
Adds Builder.xml(String body) to set UTF-8 request body and Content-Type APPLICATION_XML (mirrors json(...)).
Utilities & Minor API tweaks
core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java, core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java, core/src/main/java/com/predic8/membrane/core/util/SOAPUtil.java, core/src/main/java/com/predic8/membrane/core/util/WSDLUtil.java, core/src/main/java/com/predic8/membrane/core/config/XMLElement.java
Adds getRootCause(Throwable) to ExceptionUtil; moves XMLUtil to util.xml package and updates imports; minor interface modifier cleanup in XMLElement.
Tests updated / added
core/src/test/.../AbstractExchangeExpressionTest.java, core/src/test/.../TemplateExchangeExpressionTest.java, core/src/test/.../JsonpathExchangeExpressionTest.java, core/src/test/.../XPathExchangeExpressionTest.java, core/src/test/.../NamespacesTest.java, core/src/test/.../SetPropertyInterceptorXPathTest.java, core/src/test/.../XMLUtilTest.java
Tests updated to use InterceptorAdapter for expression evaluation; adds NamespacesTest and namespace-aware XPath/SetProperty interceptor tests.
Examples & Distribution
distribution/examples/xml/namespaces/{README.md,proxies.xml,person.xml,requests.http,membrane.sh,membrane.cmd}, distribution/src/test/.../NamespacesExampleTest.java, distribution/conf/log4j2.xml, distribution/examples/templating/json/README.md, distribution/src/test/.../VersioningSoapXsltExampleTest.java
Adds XML namespaces example, start scripts and tests; adjusts logger level and minor README/test tweaks.
Removed files
distribution/conf/convert-request-to-new-version.xslt, distribution/conf/convert-response-to-old-version.xslt, distribution/conf/security-api-v1.yml
Removes two legacy XSLT stylesheets and one OpenAPI YAML file.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Interceptor
    participant InterceptorAdapter
    participant ExchangeExpression
    participant XPathExpr
    participant XmlConfig

    Client->>Interceptor: init(Router)
    Interceptor->>Interceptor: setXmlConfig(XmlConfig)
    Interceptor->>ExchangeExpression: expression(new InterceptorAdapter(router, xmlConfig), Language, expr)
    ExchangeExpression->>XPathExpr: new XPathExchangeExpression(interceptor, xpath)
    XPathExpr->>InterceptorAdapter: request XmlConfig / NamespaceContext
    InterceptorAdapter->>XmlConfig: getNamespaces()
    XmlConfig-->>XPathExpr: NamespaceContext
    Client->>Interceptor: handleRequest(Exchange)
    Interceptor->>ExchangeExpression: evaluate(exchange)
    ExchangeExpression->>XPathExpr: evaluate with NamespaceContext
    XPathExpr-->>Interceptor: result (namespace-aware)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing focused review:
    • Router→Interceptor API surface changes (ExchangeExpression / TemplateExchangeExpression / Groovy / XPath constructors and factory call sites).
    • XML config propagation across interceptors (@MCChildElement usage and lifecycle/initialization ordering).
    • HardenedXmlParser correctness (factory configuration, entity resolver, exception wrapping).
    • IdempotencyInterceptor superclass change impacts on lifecycle and compatibility.

Possibly related PRs

Suggested reviewers

  • rrayst
  • t-burch

"🐰
I hopped through code with careful paws,
Namespaces tucked in xml laws;
Adapters carry config through,
XPath now finds prefixes true;
A tiny parser guards the burrows."

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding XML namespace declaration support for XPath expressions across multiple interceptors and related components.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch xml-namespace-declarations-for-xpath-expressions

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d05683e and 04a6490.

📒 Files selected for processing (2)
  • distribution/examples/xml/namespaces/proxies.xml (1 hunks)
  • distribution/examples/xml/namespaces/requests.http (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/examples/xml/namespaces/requests.http
  • distribution/examples/xml/namespaces/proxies.xml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (8)
distribution/conf/simple.yaml (1)

1-29: Consider adding security definitions for API hardening.

The OpenAPI specification lacks security scheme definitions. While this may be acceptable for an example configuration file, best practices recommend defining authentication/authorization mechanisms.

If this configuration is meant to be production-ready or serves as a template, consider adding security schemes:

 openapi: 3.1.0
 info:
   title: Simple Parameters API
   version: "1.0.0"
+security:
+  - bearerAuth: []
 servers:
   - url: http://localhost
+components:
+  securitySchemes:
+    bearerAuth:
+      type: http
+      scheme: bearer

If this is purely an example/test file, this can be safely ignored.

distribution/examples/xml/namespaces/membrane.cmd (1)

9-9: Consider removing redundant root check.

Line 9 checks if %dir% equals %SystemDrive%\, but this is redundant. Line 7 already properly detects when the root is reached by checking if the parent equals the current directory (which happens at any root, regardless of drive). Additionally, this check only works for the system drive and would fail to detect roots on other drives like D:\.

Apply this diff to remove the redundant check:

 set "dir=%next%"
-if "%dir%"=="%SystemDrive%\" goto notfound
 goto loop
distribution/examples/xml/namespaces/README.md (1)

12-14: Specify language for the fenced code block.

The fenced code block should specify bash or shell as the language identifier for proper syntax highlighting and consistency with markdown best practices.

Apply this diff:

     - Send:
-      ```
+      ```bash
       curl -d @person.xml localhost:2000
       ```
core/src/main/java/com/predic8/membrane/core/lang/groovy/GroovyExchangeExpression.java (1)

38-45: Guard against missing router before compiling the script.

If an expression is instantiated before the interceptor is fully wired (e.g., tests creating an InterceptorAdapter without calling init()), interceptor.getRouter() will return null, leading to a late NullPointerException when Groovy compilation tries to access the background initializer. It would be safer to fail fast with a ConfigurationException.

-        this.router = interceptor.getRouter();
+        Router router = interceptor.getRouter();
+        if (router == null) {
+            throw new ConfigurationException("Cannot compile Groovy script without an attached router.");
+        }
+        this.router = router;
core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (2)

84-86: Consider preserving exception cause for debugging.

Suppressing the stack trace (line 85) may hinder troubleshooting in production environments. While the message is preserved, the underlying cause and stack trace can be valuable for diagnosing parse failures.

If you want to avoid verbose stack traces in logs, consider preserving the cause while keeping the message concise:

-            throw new XmlParseException("Could not parse XML document: " + e.getMessage()); // No stacktrace needed
+            throw new XmlParseException("Could not parse XML document: " + e.getMessage(), e);

Then handle stack trace logging at the caller level based on log verbosity settings.


61-61: Document why UnsupportedOperationException is ignored.

The empty catch block for UnsupportedOperationException at line 61 silently swallows the exception. While this may be intentional for parsers that don't support XInclude, adding a comment would clarify the intent.

-        try { f.setXIncludeAware(false); } catch (UnsupportedOperationException ignore) {}
+        // Some parsers don't support XInclude configuration; ignore if not available
+        try { f.setXIncludeAware(false); } catch (UnsupportedOperationException ignore) {}
core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (1)

36-51: Consider parser initialization pattern.

The static parser field is initialized in the constructor (line 50), which will execute once per instance creation. Since HardenedXmlParser.getInstance() returns a singleton, this is redundant work.

Initialize the parser at the class level instead:

-    private static XmlParser parser;
+    private static final XmlParser parser = HardenedXmlParser.getInstance();
     
     private Namespaces namespaces;
     
     // Let all expressions share the same XPathFactory.
     private static final XPathFactory factory = XPathFactory.newInstance();
     
     public XPathExchangeExpression(Interceptor interceptor, String xpath) {
         super(xpath);
         
         if (interceptor instanceof XMLNamespaceSupport xns) {
             namespaces = xns.getNamespaces();
         }
-        
-        parser = HardenedXmlParser.getInstance();
     }
distribution/examples/xml/namespaces/proxies.xml (1)

1-54: Update the namespace example README to document the namespace usage pattern.

The existing README at distribution/examples/xml/namespaces/README.md is too brief. While it mentions "How to declare and use namespaces with setProperty, if, ...", it provides no actual explanation. Expand it to document:

  1. How to declare namespaces with an id attribute (the <namespaces id="ns"> block)
  2. How to reference them in interceptors using <spring:ref bean="ns"/>
  3. Which interceptors support namespace declarations (rateLimiter, log, setProperty, setHeader, if, target)

Currently it just says "Take a look at the proxies.xml file," which leaves users to reverse-engineer the pattern from the example alone.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2310068 and 7b0b78b.

📒 Files selected for processing (46)
  • core/src/main/java/com/predic8/membrane/core/http/Request.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/XMLNamespaceSupport.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (3 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/balancer/PolyglotSessionIdExtractor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/ForInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractExchangeExpressionInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractSetterInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/Namespaces.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/ratelimit/RateLimitInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/soap/SampleSoapServiceInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/groovy/GroovyExchangeExpression.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/SOAPUtil.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/WSDLUtil.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/XmlParseException.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/XmlParser.java (1 hunks)
  • core/src/test/java/com/predic8/membrane/core/interceptor/lang/NamespacesTest.java (1 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/AbstractExchangeExpressionTest.java (1 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/TemplateExchangeExpressionTest.java (2 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/jsonpath/JsonpathExchangeExpressionTest.java (1 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpressionTest.java (3 hunks)
  • core/src/test/java/com/predic8/membrane/core/util/XMLUtilTest.java (1 hunks)
  • distribution/conf/apis.yaml (1 hunks)
  • distribution/conf/log4j2.xml (1 hunks)
  • distribution/conf/simple.yaml (1 hunks)
  • distribution/examples/templating/json/README.md (2 hunks)
  • distribution/examples/xml/namespaces/README.md (1 hunks)
  • distribution/examples/xml/namespaces/membrane.cmd (1 hunks)
  • distribution/examples/xml/namespaces/membrane.sh (1 hunks)
  • distribution/examples/xml/namespaces/person.xml (1 hunks)
  • distribution/examples/xml/namespaces/proxies.xml (1 hunks)
  • distribution/examples/xml/namespaces/requests.http (1 hunks)
  • distribution/src/test/java/com/predic8/membrane/examples/withinternet/test/VersioningSoapXsltExampleTest.java (2 hunks)
  • distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1 hunks)
  • docs/ROADMAP.md (2 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-07-02T18:05:47.059Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 1947
File: distribution/tutorials/soap/membrane.sh:17-22
Timestamp: 2025-07-02T18:05:47.059Z
Learning: When using environment variable shortcuts like `$MEMBRANE_HOME` in shell scripts that look for installation directories, validate that required files (like `starter.jar` for Membrane) exist in the candidate directory before returning it. This prevents hard-to-diagnose runtime errors when the environment variable points to an invalid or stale location.

Applied to files:

  • distribution/examples/xml/namespaces/membrane.sh
  • distribution/examples/xml/namespaces/membrane.cmd
📚 Learning: 2025-08-22T15:02:24.810Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/util/TextUtil.java:119-128
Timestamp: 2025-08-22T15:02:24.810Z
Learning: XMLBeautifier.parse(InputStream) and XMLBeautifier.parse(Reader) both declare "throws Exception" in their signatures, not XMLStreamException specifically. Catching IOException is appropriate for handling IO errors during XML parsing with XMLBeautifier.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/XmlParseException.java
📚 Learning: 2025-08-22T15:02:24.810Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/util/TextUtil.java:119-128
Timestamp: 2025-08-22T15:02:24.810Z
Learning: XMLBeautifier.parse(InputStream) throws IOException specifically, not Exception. It internally wraps any XMLStreamException or other parsing exceptions in an IOException. Therefore, catching IOException in TextUtil.formatXML is the correct approach for handling XML parsing errors from InputStream.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/XmlParseException.java
📚 Learning: 2025-07-28T16:28:17.849Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 1977
File: core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java:107-109
Timestamp: 2025-07-28T16:28:17.849Z
Learning: In Java exception handling for OpenTelemetry body logging, use log.debug() level with ExceptionUtil.concatMessageAndCauseMessages(e) to log body reading failures. This prevents cluttering info logs with potentially common stream reading issues while still providing comprehensive error information when debug logging is enabled.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractSetterInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java
📚 Learning: 2025-07-11T14:18:23.761Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 1977
File: core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java:107-109
Timestamp: 2025-07-11T14:18:23.761Z
Learning: In Java exception handling, use ExceptionUtil.concatMessageAndCauseMessages(e) instead of e.getMessage() or e.getCause().getMessage() to get a complete view of the exception chain. This utility method safely concatenates all exception messages in the chain with " caused by: " separator, providing comprehensive error information for debugging without risk of NullPointerException.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java
🧬 Code graph analysis (13)
core/src/main/java/com/predic8/membrane/core/util/SOAPUtil.java (1)
core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1)
  • XMLUtil (30-85)
core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractExchangeExpressionInterceptor.java (1)
core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (1)
  • TemplateExchangeExpression (29-166)
core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2)
core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (1)
  • HardenedXmlParser (30-88)
core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1)
  • XMLUtil (30-85)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (4)
core/src/main/java/com/predic8/membrane/core/interceptor/lang/Namespaces.java (2)
  • MCElement (24-103)
  • MCElement (47-73)
core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (1)
  • MCElement (101-248)
core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (1)
  • MCElement (47-110)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (1)
  • MCElement (41-149)
core/src/main/java/com/predic8/membrane/core/util/WSDLUtil.java (1)
core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1)
  • XMLUtil (30-85)
core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (1)
core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (1)
  • TemplateExchangeExpression (29-166)
core/src/test/java/com/predic8/membrane/core/lang/jsonpath/JsonpathExchangeExpressionTest.java (1)
core/src/main/java/com/predic8/membrane/core/http/Request.java (1)
  • Request (32-369)
core/src/main/java/com/predic8/membrane/core/interceptor/soap/SampleSoapServiceInterceptor.java (1)
core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1)
  • XMLUtil (30-85)
core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java (1)
core/src/main/java/com/predic8/membrane/core/exceptions/ProblemDetails.java (1)
  • ProblemDetails (36-414)
core/src/test/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpressionTest.java (1)
core/src/main/java/com/predic8/membrane/core/http/Request.java (1)
  • Request (32-369)
core/src/main/java/com/predic8/membrane/core/interceptor/lang/Namespaces.java (5)
core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (1)
  • MCElement (101-248)
core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (1)
  • MCElement (47-110)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (1)
  • MCElement (41-149)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (1)
  • MCElement (29-93)
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (2)
  • MCElement (43-252)
  • MCElement (226-238)
core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractSetterInterceptor.java (2)
core/src/main/java/com/predic8/membrane/core/exceptions/ProblemDetails.java (1)
  • ProblemDetails (36-414)
core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java (1)
  • ExceptionUtil (20-40)
core/src/test/java/com/predic8/membrane/core/interceptor/lang/NamespacesTest.java (1)
core/src/main/java/com/predic8/membrane/core/util/CollectionsUtil.java (1)
  • CollectionsUtil (23-70)
🪛 Checkov (3.2.334)
distribution/conf/simple.yaml

[high] 1-29: Ensure that the global security field has rules defined

(CKV_OPENAPI_4)


[high] 1-29: Ensure that security operations is not empty.

(CKV_OPENAPI_5)


[medium] 16-20: Ensure that arrays have a maximum number of items

(CKV_OPENAPI_21)

🪛 markdownlint-cli2 (0.18.1)
distribution/examples/xml/namespaces/README.md

12-12: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Shellcheck (0.11.0)
distribution/examples/xml/namespaces/membrane.sh

[warning] 8-8: Remove space after = if trying to assign a value (for empty string, use var='' ... ).

(SC1007)

🔇 Additional comments (52)
distribution/examples/templating/json/README.md (1)

15-15: Step numbering shift is appropriate given the new step 2.

The renumbering of steps 3→3, 4→4, and 5→5 follows logically from introducing step 2 (viewing proxies.xml before execution). The documentation now guides users through understanding the configuration before running the example, which is a sensible pedagogical improvement.

Also applies to: 17-17, 29-29

core/src/main/java/com/predic8/membrane/core/http/Request.java (1)

314-318: LGTM! Clean implementation following the established pattern.

The xml() method correctly mirrors the json() method's approach, setting the body content and appropriate Content-Type header. This provides a convenient way to build XML requests and aligns well with the PR's objective of enhancing XML namespace support.

distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (2)

1-13: License header is correct.

Standard Apache License 2.0 header is properly formatted.


18-23: Code structure is correct and verified.

The example directory distribution/examples/xml/namespaces/ exists at the expected location, and the getExampleDirName() method correctly references it. No changes needed.

distribution/examples/xml/namespaces/membrane.sh (2)

8-8: Shellcheck warning is a false positive.

The syntax CDPATH= is intentional and correct. It temporarily sets CDPATH to empty for just that command to prevent CDPATH pollution when computing the script's directory. This is a well-known shell idiom.


10-18: LGTM! Correct implementation with proper validation.

The upward directory traversal correctly validates that both starter.jar and scripts/run-membrane.sh exist before using a directory, which prevents hard-to-diagnose runtime errors. This follows the established learning. Based on learnings

distribution/examples/xml/namespaces/membrane.cmd (1)

5-5: LGTM! Proper validation of required files.

The script correctly validates that both starter.jar and scripts\run-membrane.cmd exist before using the directory, which prevents hard-to-diagnose runtime errors. Based on learnings

distribution/conf/log4j2.xml (1)

12-14: INFO level aligns with production defaults.

Keeps the HTTP client transport logs quieter unless problems arise.

core/src/main/java/com/predic8/membrane/core/interceptor/ratelimit/RateLimitInterceptor.java (1)

97-97: Passing the interceptor instance matches the new factory contract.

Ensures namespace-aware evaluation has access to this interceptor’s context.

docs/ROADMAP.md (1)

34-34: Appreciate the explicit SessionManagerTest TODO.

Having it on the roadmap makes the migration visible.

distribution/src/test/java/com/predic8/membrane/examples/withinternet/test/VersioningSoapXsltExampleTest.java (1)

57-58: Conditional logging tightens diagnostics.

.log().ifValidationFails(ALL) keeps green runs quiet while preserving failure detail.

distribution/examples/xml/namespaces/person.xml (1)

1-6: Nice, concise namespace example.

This will help users see prefix declarations in practice.

core/src/test/java/com/predic8/membrane/core/interceptor/lang/NamespacesTest.java (1)

38-41: Test covers the essential namespace lookups.

Great to see getNamespaceURI, getPrefix, and getPrefixes all asserted.

core/src/main/java/com/predic8/membrane/core/interceptor/XMLNamespaceSupport.java (1)

1-9: Clean contract for namespace-aware interceptors.

This keeps namespace propagation explicit and easy to implement.

core/src/main/java/com/predic8/membrane/core/util/xml/parser/XmlParseException.java (1)

1-34: LGTM!

Clean unchecked exception implementation with clear purpose documented in the javadoc. The wrapping of SAXException and IOException as a RuntimeException simplifies error handling for callers.

core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractSetterInterceptor.java (2)

54-56: Root cause extraction improves error messages.

Extracting the root cause provides clearer error messages by avoiding wrapper exception noise. The use of ExceptionUtil.getRootCause() aligns with the pattern used elsewhere in the codebase.


56-56: Verify that info-level logging is appropriate for expression evaluation failures.

The logging level changed from error to info. While this reduces log noise, expression evaluation failures might warrant higher visibility in production environments, especially when failOnError is true and requests are being aborted.

Consider whether these failures should remain at error level when failOnError=true to ensure operational visibility of rejected requests.

distribution/conf/apis.yaml (1)

1-509: LGTM!

The configuration demonstrates comprehensive API gateway capabilities with diverse interceptor usage patterns including logging, scripting (Groovy/JavaScript), templating, authentication, and protection mechanisms. The structure is clear and follows the expected YAML schema.

core/src/main/java/com/predic8/membrane/core/util/SOAPUtil.java (1)

32-32: LGTM!

The static import path update reflects the package relocation of XMLUtil to the xml subpackage. No functional changes.

distribution/examples/xml/namespaces/requests.http (1)

1-9: LGTM!

Clear example demonstrating XML namespace usage with multiple namespace prefixes (per: and ns1:). The request structure is well-formed.

core/src/main/java/com/predic8/membrane/core/interceptor/soap/SampleSoapServiceInterceptor.java (1)

37-37: LGTM!

The static import path update reflects the package relocation of XMLUtil to the xml subpackage. No functional changes.

core/src/test/java/com/predic8/membrane/core/lang/jsonpath/JsonpathExchangeExpressionTest.java (2)

119-120: LGTM!

Test correctly updated to use InterceptorAdapter wrapper, aligning with the refactored ExchangeExpression.newInstance() API signature. The functional test logic remains unchanged.


124-125: LGTM!

Test correctly updated to use InterceptorAdapter wrapper, consistent with the API changes throughout the PR.

core/src/main/java/com/predic8/membrane/core/util/WSDLUtil.java (1)

27-27: LGTM!

The import path update correctly reflects the relocation of XMLUtil to the util.xml package.

core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1)

14-14: LGTM!

The package relocation to util.xml improves code organization by grouping XML-related utilities together.

core/src/test/java/com/predic8/membrane/core/util/XMLUtilTest.java (1)

16-16: LGTM!

The wildcard import correctly references the relocated XMLUtil package.

core/src/test/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpressionTest.java (1)

118-138: Good test coverage for namespace handling.

The new test correctly validates XPath evaluation with namespaced XML using the local-name() function. This provides essential coverage for the XML namespace support feature.

core/src/main/java/com/predic8/membrane/core/interceptor/balancer/PolyglotSessionIdExtractor.java (2)

24-25: LGTM!

The import consolidation using wildcards is consistent with the codebase style.


36-36: LGTM!

The refactor to use InterceptorAdapter aligns with the broader PR changes and enables proper namespace context propagation for expression evaluation.

core/src/test/java/com/predic8/membrane/core/lang/AbstractExchangeExpressionTest.java (1)

67-80: LGTM!

The test helper methods have been consistently updated to use InterceptorAdapter, maintaining uniform test infrastructure while supporting the new namespace-aware expression evaluation.

core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (4)

23-25: LGTM!

The wildcard imports consolidate related classes and align with the codebase style.


60-60: LGTM!

The Namespaces field addition enables XML namespace support for API expressions.


86-86: LGTM!

The ExchangeExpression initialization correctly passes the namespaces via InterceptorAdapter, enabling namespace-aware expression evaluation for API test scripts.


240-251: LGTM!

The namespace getter/setter methods are properly annotated with MCChildElement, enabling XML configuration of namespaces for XPath expressions. The Javadoc clearly describes the purpose.

core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractExchangeExpressionInterceptor.java (1)

29-31: Good call moving to an interceptor-supplied context.

Passing this keeps the ExchangeExpression factory aligned with the new namespace-aware API surface. Nicely done.

core/src/main/java/com/predic8/membrane/core/util/xml/parser/XmlParser.java (1)

20-34: Clean, focused parser contract.

The interface and javadoc clearly document the hardened, thread-safe expectations—this will make future implementations straightforward.

core/src/main/java/com/predic8/membrane/core/interceptor/flow/ForInterceptor.java (1)

55-63: Alignment with interceptor-based expressions looks good.

Switching to ExchangeExpression.newInstance(this, …) keeps the namespace-aware plumbing consistent across flow interceptors.

core/src/test/java/com/predic8/membrane/core/lang/TemplateExchangeExpressionTest.java (1)

45-70: Solid coverage update.

Using InterceptorAdapter in the tests mirrors the production wiring and protects the new constructor signature; thanks for keeping the fixtures in sync.

core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (1)

42-148: Namespace plumbing looks consistent.

Implementing XMLNamespaceSupport directly in IfInterceptor and feeding the interceptor instance into the expression factory should make XPath use much easier to configure.

core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (2)

102-119: LGTM! Clean integration of namespace support.

The Target class correctly implements XMLNamespaceSupport and uses InterceptorAdapter to pass namespace context during expression initialization. This aligns well with the broader namespace support framework introduced in this PR.


240-247: LGTM! Proper namespace accessor implementation.

The getter/setter methods for namespaces follow the established pattern and are properly annotated with @MCChildElement for XML configuration support.

core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (2)

48-58: LGTM! Namespace support properly integrated.

The implementation correctly adopts XMLNamespaceSupport and uses InterceptorAdapter to pass namespace context during expression initialization, consistent with the broader namespace support framework.


98-109: LGTM! Well-documented namespace configuration.

The Javadoc clearly describes the purpose of the namespace declarations for XPath expressions, and the annotation is correctly configured.

core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (1)

25-58: LGTM! Base class properly extended with namespace support.

The abstract class now provides namespace support to all language interceptors through the XMLNamespaceSupport interface. The implementation is clean and allows subclasses to inherit this functionality.

core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (2)

30-41: LGTM! Namespace support correctly implemented.

The Case class properly adopts the XMLNamespaceSupport interface and uses InterceptorAdapter to provide namespace context during expression evaluation, consistent with the framework pattern.


81-92: LGTM! Namespace accessors properly implemented.

The setter/getter methods follow the established pattern with appropriate annotations and documentation.

core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2)

88-96: LGTM! Thread-safe XPath evaluation with namespace support.

The implementation correctly creates a fresh XPath instance for each evaluation (thread-safe) and properly applies the namespace context when available. The use of HardenedXmlParser ensures XXE protection.


43-48: Clean namespace extraction from interceptor.

The pattern of checking if the interceptor implements XMLNamespaceSupport and extracting namespaces is clean and follows the framework design well.

core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java (2)

68-93: Well-designed adapter for backward compatibility.

The InterceptorAdapter inner class provides a clean bridge for contexts where an Interceptor is not available, wrapping a Router and optional Namespaces. The two-constructor pattern (with/without namespaces) is convenient and follows good design practices.


52-67: Breaking change successfully propagated throughout codebase.

All 16 usages of ExchangeExpression.newInstance() have been updated to use the new Interceptor parameter instead of Router. Callers properly provide either:

  • Direct interceptor instances (e.g., this in interceptor classes)
  • Wrapped router via InterceptorAdapter (in non-interceptor contexts)
  • null for languages that don't require an interceptor (SPEL, JSONPATH)

No remaining calls with the old Router signature exist. The migration is complete and consistent.

core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java (1)

49-55: Interceptor-scoped expression init looks solid.

Passing this into ExchangeExpression.newInstance keeps the namespace context attached to the interceptor, aligning with the new language/ns plumbing. Looks good from my side.

core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (1)

95-104: Nested expressions now inherit namespace context.

Threading the interceptor through ${…} token instantiation prevents namespace loss in embedded expressions. Nice work.

Comment thread distribution/conf/simple.yaml
Comment thread distribution/examples/xml/namespaces/membrane.cmd

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (1)

52-69: Ensure parsing exceptions are properly handled.

The evaluate method catches XPathExpressionException on line 65, but parser.parse() on line 93 can throw XmlParseException (a runtime exception), which would bypass this catch block and propagate uncaught. This breaks the clean error reporting established by ExchangeExpressionException.

Apply this diff to handle parsing failures consistently:

         try {
             if (Boolean.class.isAssignableFrom(type)) {
                 return type.cast( evalutateAndCast(msg, BOOLEAN));
             }
             if (String.class.isAssignableFrom(type)) {
                 return type.cast(evalutateAndCast(msg, STRING));
             }
             if (Object.class.isAssignableFrom(type)) {
                 return type.cast( evaluateAndCastToObject( msg));
             }
             throw  new RuntimeException("Should not Happen!");
-        } catch (XPathExpressionException xee) {
+        } catch (XPathExpressionException | XmlParseException xee) {
             throw new ExchangeExpressionException(expression,xee)
                     .body(msg.getBodyAsStringDecoded())
                     .stacktrace(false);
         }
🧹 Nitpick comments (2)
core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java (1)

16-18: Remove unused imports.

The imports com.predic8.membrane.core.util.xml.parser.* and java.util.* are not referenced in this file.

Apply this diff:

-import com.predic8.membrane.core.util.xml.parser.*;
-
-import java.util.*;
-
 public class ExceptionUtil {
core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (1)

17-18: Consider using explicit imports instead of wildcards.

Wildcard imports can obscure which classes are actually used and may lead to naming conflicts as the packages evolve. Explicit imports improve code clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b0b78b and 6347d21.

📒 Files selected for processing (7)
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/Namespaces.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (1 hunks)
  • distribution/examples/xml/namespaces/README.md (1 hunks)
  • distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/Namespaces.java
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-11T14:18:23.761Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 1977
File: core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java:107-109
Timestamp: 2025-07-11T14:18:23.761Z
Learning: In Java exception handling, use ExceptionUtil.concatMessageAndCauseMessages(e) instead of e.getMessage() or e.getCause().getMessage() to get a complete view of the exception chain. This utility method safely concatenates all exception messages in the chain with " caused by: " separator, providing comprehensive error information for debugging without risk of NullPointerException.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java
📚 Learning: 2025-07-28T16:28:17.849Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 1977
File: core/src/main/java/com/predic8/membrane/core/interceptor/opentelemetry/OpenTelemetryInterceptor.java:107-109
Timestamp: 2025-07-28T16:28:17.849Z
Learning: In Java exception handling for OpenTelemetry body logging, use log.debug() level with ExceptionUtil.concatMessageAndCauseMessages(e) to log body reading failures. This prevents cluttering info logs with potentially common stream reading issues while still providing comprehensive error information when debug logging is enabled.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java
🧬 Code graph analysis (1)
core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2)
core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (1)
  • HardenedXmlParser (30-92)
core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1)
  • XMLUtil (30-85)
🪛 LanguageTool
distribution/examples/xml/namespaces/README.md

[grammar] ~4-~4: Ensure spelling is correct
Context: ...clare and use namespaces. The namespace decarations can be used in: - setProperty - setHea...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (4)
distribution/examples/xml/namespaces/README.md (1)

16-27: Clear and well-structured documentation.

The running instructions are easy to follow, with step-by-step guidance referencing the relevant files (person.xml, proxies.xml). The note about requests.http availability adds helpful context.

core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java (1)

34-42: LGTM! Null guard properly addresses the previous concern.

The null check on line 35 prevents NPE when callers pass null or exception.getCause() returns null. The loop correctly traverses the cause chain while avoiding cycles.

core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (1)

86-94: LGTM! Thread-safe XPath evaluation with namespace support.

Creating a fresh XPath instance per evaluation (line 87) correctly avoids thread-safety issues. The conditional namespace context binding (lines 89-91) integrates cleanly with the new XMLNamespaceSupport infrastructure.

core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (1)

47-58: LGTM! Clean integration of XML namespace support.

The @MCChildElement(allowForeign = true) annotation on line 51 correctly allows namespace declarations in XML configuration, and the getter/setter pair properly implements the XMLNamespaceSupport interface.

Comment thread distribution/examples/xml/namespaces/README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (1)

89-93: Preserve the original parse exception.

Re-throwing without the cause drops the stack trace and repeats a previously flagged issue. Please chain the caught exception so downstream diagnostics aren’t blind.

-        } catch (Exception e) {
-            throw new XmlParseException("Could not parse XML document: " + e.getMessage()); // No stacktrace needed
+        } catch (Exception e) {
+            throw new XmlParseException("Could not parse XML document: " + e.getMessage(), e);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6347d21 and 74ddf93.

📒 Files selected for processing (5)
  • core/src/main/java/com/predic8/membrane/core/interceptor/XMLNamespaceSupport.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (1 hunks)
  • distribution/examples/xml/namespaces/README.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/examples/xml/namespaces/README.md
  • core/src/main/java/com/predic8/membrane/core/util/ExceptionUtil.java
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-08-22T15:02:24.810Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/util/TextUtil.java:119-128
Timestamp: 2025-08-22T15:02:24.810Z
Learning: XMLBeautifier.parse(InputStream) and XMLBeautifier.parse(Reader) both declare "throws Exception" in their signatures, not XMLStreamException specifically. Catching IOException is appropriate for handling IO errors during XML parsing with XMLBeautifier.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java
📚 Learning: 2025-08-22T15:02:24.810Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/util/TextUtil.java:119-128
Timestamp: 2025-08-22T15:02:24.810Z
Learning: XMLBeautifier.parse(InputStream) throws Exception, not XMLStreamException specifically, so catching IOException in TextUtil.formatXML is appropriate for handling IO errors during XML parsing.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
core/src/main/java/com/predic8/membrane/core/interceptor/balancer/PolyglotSessionIdExtractor.java (1)

24-40: Fix the invalid import (compilation blocker).
import com.predic8.membrane.core.lang.ExchangeExpression.*; is not a legal Java import (on-demand imports can only target packages). As a result, Language is still unresolved and the class no longer compiles. Please remove this line and import the nested enum explicitly.

-import com.predic8.membrane.core.lang.*;
-import com.predic8.membrane.core.lang.ExchangeExpression.*;
+import com.predic8.membrane.core.lang.*;
+import com.predic8.membrane.core.lang.ExchangeExpression.Language;
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (1)

23-40: Correct the ExchangeExpression import to restore compilation.
Same issue here: import com.predic8.membrane.core.lang.ExchangeExpression.*; is an invalid non-static import, so the nested Language type is still missing and the file will not compile. Please replace it with an explicit import of the nested enum.

-import com.predic8.membrane.core.interceptor.lang.*;
-import com.predic8.membrane.core.lang.*;
-import com.predic8.membrane.core.lang.ExchangeExpression.*;
+import com.predic8.membrane.core.interceptor.lang.*;
+import com.predic8.membrane.core.lang.*;
+import com.predic8.membrane.core.lang.ExchangeExpression.Language;
core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (1)

88-105: Remove merge conflict from parseTokens().

The parser still includes <<<<<<< HEAD / ======= / >>>>>>>. This prevents compilation and leaves ambiguity about which factory to use. Please resolve it and wire the tokens to the new factory:

-<<<<<<< HEAD
-                tokens.add(new Expression(ExchangeExpression.newInstance(interceptor, language, expr)));
-=======
-                tokens.add(new Expression(expression(router, language, expr)));
->>>>>>> f78bb2c5a6937831602bd693024f03f9f2acad2d
+                tokens.add(new Expression(ExchangeExpression.newInstance(interceptor, language, expr)));
core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java (1)

30-61: Resolve both merge conflicts (imports and init()).

This file still contains conflict markers in the import block and inside init(), so it will not compile. Please settle the conflicts and keep the Interceptor-based expression initialization:

-import static com.predic8.membrane.core.interceptor.Outcome.ABORT;
-<<<<<<< HEAD
-=======
-import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE;
-import static com.predic8.membrane.core.lang.ExchangeExpression.Language.SPEL;
-import static com.predic8.membrane.core.lang.ExchangeExpression.expression;
->>>>>>> f78bb2c5a6937831602bd693024f03f9f2acad2d
+import static com.predic8.membrane.core.interceptor.Outcome.ABORT;
+import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE;

@@
-<<<<<<< HEAD
-        exchangeExpression = ExchangeExpression.newInstance(this, language, key);
-=======
-        exchangeExpression = expression(router, language, key);
->>>>>>> f78bb2c5a6937831602bd693024f03f9f2acad2d
+        exchangeExpression = ExchangeExpression.newInstance(this, language, key);

Also remove the obsolete static import for ExchangeExpression.expression if the helper no longer exists.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74ddf93 and 150ab96.

📒 Files selected for processing (12)
  • core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (3 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/balancer/PolyglotSessionIdExtractor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/ForInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/ratelimit/RateLimitInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (4 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/AbstractExchangeExpressionTest.java (2 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/jsonpath/JsonpathExchangeExpressionTest.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/src/test/java/com/predic8/membrane/core/lang/AbstractExchangeExpressionTest.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java
🧰 Additional context used
🧬 Code graph analysis (2)
core/src/test/java/com/predic8/membrane/core/lang/jsonpath/JsonpathExchangeExpressionTest.java (1)
core/src/main/java/com/predic8/membrane/core/http/Request.java (1)
  • Request (32-369)
core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java (1)
core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (1)
  • AbstractLanguageInterceptor (23-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)

Comment thread core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java Outdated
Comment thread core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 150ab96 and a3075f9.

📒 Files selected for processing (13)
  • core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (3 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/balancer/PolyglotSessionIdExtractor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/ForInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/ratelimit/RateLimitInterceptor.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (4 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/AbstractExchangeExpressionTest.java (1 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/jsonpath/JsonpathExchangeExpressionTest.java (1 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpressionTest.java (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/ForInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java
  • core/src/test/java/com/predic8/membrane/core/lang/AbstractExchangeExpressionTest.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/ratelimit/RateLimitInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java
  • core/src/test/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpressionTest.java
🧰 Additional context used
🧬 Code graph analysis (2)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (3)
core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (1)
  • MCElement (49-112)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (1)
  • MCElement (42-150)
core/src/main/java/com/predic8/membrane/core/interceptor/lang/Namespaces.java (2)
  • MCElement (24-102)
  • MCElement (46-72)
core/src/test/java/com/predic8/membrane/core/lang/jsonpath/JsonpathExchangeExpressionTest.java (1)
core/src/main/java/com/predic8/membrane/core/http/Request.java (1)
  • Request (32-369)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (java)
  • GitHub Check: Automated tests
🔇 Additional comments (7)
core/src/main/java/com/predic8/membrane/core/interceptor/idempotency/IdempotencyInterceptor.java (2)

43-43: LGTM! Architectural change enables namespace support.

Extending AbstractLanguageInterceptor is the appropriate refactoring to enable XML namespace support for XPath expressions, aligning with the PR objectives. This eliminates the need for a local language field and integrates namespace propagation through the parent class.


50-59: Expression initialization correctly refactored for namespace support.

The change from expression(router, language, key) to expression(this, language, key) enables namespace-aware expression construction by passing the interceptor (which implements XMLNamespaceSupport through AbstractLanguageInterceptor). The inherited language field is safely initialized at the class level with default value SPEL in AbstractLanguageInterceptor, ensuring it's available when used on line 54.

core/src/main/java/com/predic8/membrane/core/interceptor/balancer/PolyglotSessionIdExtractor.java (1)

36-36: Adapter context update aligns with new namespace flow.

Switching to InterceptorAdapter keeps this extractor in step with the namespace-aware expression pipeline while preserving existing behavior. Nicely done.

core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (1)

85-92: Namespaces hook mirrors other interceptors.

Bringing Case onto XMLNamespaceSupport with the namespaces child element keeps XPath cases consistent with the broader namespace story. Looks spot on.

core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (1)

59-107: Init path now honors optional namespaces.

By funnelling initialization through InterceptorAdapter(router, namespaces), the extractor cleanly picks up namespace bindings without regressing existing configurations. All good here.

core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (1)

41-52: Template tokens now share interceptor context.

Passing the interceptor through newInstance and into parseTokens keeps embedded expressions on the same namespace-aware footing as their parents. Thanks for tightening that integration.

core/src/test/java/com/predic8/membrane/core/lang/jsonpath/JsonpathExchangeExpressionTest.java (1)

120-138: Tests cover adapter-based expression construction.

Updating the JSONPath tests to build expressions through InterceptorAdapter(router) keeps the suite aligned with the production factory changes. Great to see the coverage adjusted.

@predic8 predic8 requested a review from rrayst November 2, 2025 20:01
@membrane-ci-server

Copy link
Copy Markdown

This pull request needs "/ok-to-test" from an authorized committer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
core/src/test/java/com/predic8/membrane/core/lang/xpath/SetPropertyInterceptorXPathTest.java (1)

34-34: Remove unused field.

The ObjectMapper om field is declared but never used in any of the tests.

Apply this diff to remove the unused field:

-    private ObjectMapper om = new ObjectMapper();
     private Exchange exc;
distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (2)

123-144: Strengthen the assertion for the no-namespace test case.

The assertion containsString("from") on line 142 is too weak and could match unintended responses (e.g., error messages like "Response from server"). Consider asserting the exact expected output when namespace-aware XPath fails to match, or at minimum use a more specific substring that uniquely identifies the expected behavior.

For example:

-            .body(containsString("from"));
+            .body(equalTo("Expected output when namespaces don't match"));

Or document the expected behavior and assert a more specific pattern that distinguishes success from other "from"-containing responses.


31-190: Consider extracting common test structure into a helper method.

All test methods follow an identical pattern with only the XML body and expected response varying. Extracting this into a helper method would reduce duplication and improve maintainability.

Example refactor:

private void assertNamespaceExtraction(String xmlBody, String expectedResponseSubstring) {
    // @formatter:off
    given()
        .contentType(TEXT_XML)
        .body(xmlBody)
        .post("http://localhost:2000")
    .then()
        .log().ifValidationFails(ALL)
        .statusCode(200)
        .body(containsString(expectedResponseSubstring));
    // @formatter:on
}

@Test
void namespaceAwareXPathExtraction() {
    String xmlBody = """
        <per:person id="77" xmlns:per="https://predic8.de/person">
          <per:name>Hans</per:name>
          <ns1:address xmlns:ns1="https://predic8.de/address">
            <ns1:city>Cologne</ns1:city>
          </ns1:address>
        </per:person>
        """;
    
    assertNamespaceExtraction(xmlBody, "Hans from Cologne");
}

This would make the tests more concise while maintaining clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b808382 and c9e9734.

📒 Files selected for processing (5)
  • core/src/test/java/com/predic8/membrane/core/lang/xpath/SetPropertyInterceptorXPathTest.java (1 hunks)
  • distribution/conf/convert-request-to-new-version.xslt (0 hunks)
  • distribution/conf/convert-response-to-old-version.xslt (0 hunks)
  • distribution/conf/security-api-v1.yml (0 hunks)
  • distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1 hunks)
💤 Files with no reviewable changes (3)
  • distribution/conf/convert-request-to-new-version.xslt
  • distribution/conf/security-api-v1.yml
  • distribution/conf/convert-response-to-old-version.xslt
🧰 Additional context used
🧬 Code graph analysis (1)
distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1)
core/src/main/java/com/predic8/membrane/core/http/MimeType.java (1)
  • MimeType (31-214)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (4)
core/src/test/java/com/predic8/membrane/core/lang/xpath/SetPropertyInterceptorXPathTest.java (2)

37-107: Excellent test coverage and structure.

The test organization effectively demonstrates namespace handling in XPath:

  • Basic scenario without namespaces establishes the baseline
  • Multiple strategies for namespaced XML (local-name(), namespace-uri(), proper prefix declarations)
  • Clear comparison between incorrect usage (prefix without declaration) and correct usage (with namespace configuration)
  • Comprehensive error handling validation

The progression of test cases provides good documentation of how to work with namespaces in XPath.


99-106: Thorough error handling validation.

The test properly validates multiple aspects of error handling:

  • Control flow (ABORT outcome)
  • HTTP semantics (500 status)
  • User experience (error message contains both the problematic expression and identifies the unknown prefix)

This ensures users receive actionable error feedback when namespace prefixes are not properly configured.

distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (2)

24-29: LGTM! Well-structured test class setup.

The test class properly extends the sample test base class and correctly references the example directory for namespace testing.


31-121: Excellent coverage of positive namespace scenarios.

The test cases comprehensively validate namespace-aware XPath extraction across multiple scenarios: basic prefixed namespaces, data variations, different prefix bindings, and default namespaces. The assertions are specific and appropriate for integration testing.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (2)

51-51: Consider more specific assertions for stronger validation.

The current assertions using containsString() work well for integration tests and are less brittle. However, if you want more precise validation, you could assert the exact response body format or structure.

For example:

.body(equalTo("Hans from Cologne"))
// or use XPath/XML matchers if the response is XML

This is optional—the current approach is acceptable for example tests.

Also applies to: 74-74, 97-97, 120-120, 144-144, 168-168


32-170: Optional: Extract helper method to reduce duplication.

If you anticipate adding more test cases, consider extracting a helper method to reduce duplication:

private void assertNamespaceExtraction(String xmlBody, String expectedBodyContent) {
    given()
        .contentType(TEXT_XML)
        .body(xmlBody)
        .post("http://localhost:2000")
    .then()
        .log().ifValidationFails(ALL)
        .statusCode(200)
        .body(containsString(expectedBodyContent));
}

However, the current self-contained approach is perfectly acceptable for test code clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9e9734 and 4aebbb0.

📒 Files selected for processing (1)
  • distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1)
core/src/main/java/com/predic8/membrane/core/http/MimeType.java (1)
  • MimeType (31-214)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (2)
distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (2)

25-30: Excellent test class structure.

The class correctly extends AbstractSampleMembraneStartStopTestcase and configures the example directory. This will ensure the Membrane API Gateway starts with the XML namespaces example configuration before running tests.


32-170: Comprehensive test coverage of XML namespace functionality.

The test suite thoroughly validates the PR's core feature with excellent scenario coverage:

  • ✅ Basic namespace-aware XPath extraction
  • ✅ Different XML prefixes with the same namespace URIs (proving URI-based matching)
  • ✅ Default namespace handling
  • ✅ Graceful degradation when namespace URIs don't match
  • ✅ XPath attribute extraction to response headers

Each test is self-contained, follows the given-when-then pattern, and uses appropriate REST-assured assertions.

@christiangoerdes christiangoerdes linked an issue Nov 3, 2025 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1)

125-146: Consider strengthening the assertion for clearer intent.

The test correctly validates behavior with a mismatched namespace URI, but the assertion containsString("Hans from") is somewhat weak—it doesn't explicitly verify that the city extraction failed.

Consider one of these alternatives for clarity:

Option 1: Add a negative assertion

     .statusCode(200)
     .body(containsString("Hans from"))
+    .body(not(containsString("Cologne")));

Option 2: Check for empty/missing city explicitly

-    .body(containsString("Hans from"));
+    .body(containsString("Hans from "))  // trailing space indicates missing city

Choose the option that matches the actual example behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4aebbb0 and aa3ad0d.

📒 Files selected for processing (2)
  • distribution/examples/xml/namespaces/proxies.xml (1 hunks)
  • distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • distribution/examples/xml/namespaces/proxies.xml
🧰 Additional context used
🧬 Code graph analysis (1)
distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (1)
core/src/main/java/com/predic8/membrane/core/http/MimeType.java (1)
  • MimeType (31-214)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (4)
distribution/src/test/java/com/predic8/membrane/examples/withoutinternet/test/xml/namespaces/NamespacesExampleTest.java (4)

1-30: Well-structured test setup.

The class correctly extends the example test base class and properly configures the example directory. Imports are clean and follow established patterns.


32-76: Solid baseline tests for namespace-aware XPath.

These tests establish the happy path for namespace-aware XML processing. Testing with two different datasets (Hans/Cologne and Maria/Berlin) confirms consistent behavior.


78-122: Excellent coverage of namespace edge cases.

These tests validate critical namespace behaviors:

  • differentPrefixesStillMatch confirms namespace URIs are matched, not prefix names (essential for interoperability)
  • defaultNamespaceOnPerson ensures default namespace handling works correctly (common in real-world XML)

148-170: Good coverage of attribute extraction.

This test validates XPath attribute extraction (the @id syntax) and confirms the value flows correctly from XML attribute to response header. Nice complement to the element-content extraction in other tests.

Comment thread core/src/main/java/com/predic8/membrane/core/interceptor/lang/Namespaces.java Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (1)

27-27: Initialize namespaces list to prevent NullPointerException.

The namespaces field is not initialized and will remain null if setNamespace() is never called. This causes NPE in NamespaceContextImpl methods (lines 78, 87, 96) that call namespaces.stream().

Apply this diff to initialize the field:

-    private List<Namespace> namespaces;
+    private List<Namespace> namespaces = new ArrayList<>();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79d26cf and 4b7b720.

📒 Files selected for processing (14)
  • core/src/main/java/com/predic8/membrane/core/config/XMLElement.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/config/xml/XmlConfig.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/XMLSupport.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (3 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (4 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2 hunks)
  • core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (5 hunks)
  • core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (4 hunks)
  • core/src/test/java/com/predic8/membrane/core/interceptor/lang/NamespacesTest.java (1 hunks)
  • core/src/test/java/com/predic8/membrane/core/lang/xpath/SetPropertyInterceptorXPathTest.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • core/src/main/java/com/predic8/membrane/core/config/XMLElement.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • core/src/test/java/com/predic8/membrane/core/lang/xpath/SetPropertyInterceptorXPathTest.java
  • core/src/test/java/com/predic8/membrane/core/interceptor/lang/NamespacesTest.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java
🧰 Additional context used
🧬 Code graph analysis (4)
core/src/main/java/com/predic8/membrane/core/config/xml/XmlConfig.java (6)
core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (2)
  • MCElement (24-102)
  • MCElement (46-72)
core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (1)
  • MCElement (50-115)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (1)
  • MCElement (41-151)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (1)
  • MCElement (29-95)
core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (2)
  • MCElement (47-257)
  • MCElement (230-242)
core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (1)
  • MCElement (100-253)
core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (5)
core/src/main/java/com/predic8/membrane/core/config/xml/XmlConfig.java (1)
  • MCElement (5-18)
core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (1)
  • MCElement (50-115)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (1)
  • MCElement (41-151)
core/src/main/java/com/predic8/membrane/core/interceptor/flow/choice/Case.java (1)
  • MCElement (29-95)
core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (1)
  • MCElement (100-253)
core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2)
core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (1)
  • HardenedXmlParser (30-99)
core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1)
  • XMLUtil (30-85)
core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (1)
core/src/main/java/com/predic8/membrane/core/lang/TemplateExchangeExpression.java (1)
  • TemplateExchangeExpression (30-167)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (24)
core/src/main/java/com/predic8/membrane/core/interceptor/lang/AbstractLanguageInterceptor.java (3)

24-24: LGTM! Clean interface implementation.

The addition of XMLSupport to the class signature is appropriate for enabling XML configuration across language interceptors.


46-59: LGTM! Well-documented XML configuration support.

The getter and setter methods are properly annotated and documented. The allowForeign = true parameter on @MCChildElement correctly allows foreign XML elements, and order = 10 ensures proper element ordering.


30-30: Null-safety concern already addressed in code.

Verification confirmed that the xmlConfig field is properly guarded with null checks. The only direct access to xmlConfig properties (XPathExchangeExpression.java:90) is already protected by a conditional check on line 89: if (xmlConfig != null). Subclasses do not directly access the field unsafely—they delegate to expression methods which handle null-safety internally. No additional safeguards are required.

core/src/main/java/com/predic8/membrane/core/interceptor/XMLSupport.java (1)

19-24: LGTM! Clean and minimal interface design.

The XMLSupport interface provides a clear contract for XML configuration propagation across interceptors. The design is simple and follows Java interface best practices.

core/src/main/java/com/predic8/membrane/core/interceptor/flow/IfInterceptor.java (3)

42-42: LGTM! Consistent XMLSupport implementation.

The addition of XMLSupport interface enables XML namespace configuration for XPath expressions in if conditions.


58-58: LGTM! Correct context propagation.

The expression initialization now uses this instead of router, which allows the XML configuration to be propagated through the XMLSupport interface. This is the correct approach for enabling namespace-aware XPath expressions.


137-150: LGTM! Well-documented XML configuration support.

The XML configuration methods are properly annotated and documented, consistent with the pattern used in other interceptors.

core/src/main/java/com/predic8/membrane/core/proxies/AbstractServiceProxy.java (3)

101-101: LGTM! Target class gains XML configuration support.

The implementation of XMLSupport enables XML namespace configuration for URL expressions in target definitions.


114-119: LGTM! Proper XML config propagation through InterceptorAdapter.

The expression initialization correctly uses InterceptorAdapter(router, xmlConfig) to propagate XML configuration to template expressions. The null check on url ensures the adapter is only created when needed.


239-252: LGTM! Consistent XML configuration implementation.

The XML configuration methods follow the established pattern with proper annotations and documentation.

core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (3)

36-36: LGTM! Secure XML parser usage.

Using the singleton HardenedXmlParser.getInstance() ensures secure XML parsing with XXE protection across all XPath evaluations.


43-49: LGTM! Clean XML config extraction.

The constructor properly extracts XML configuration from interceptors that implement XMLSupport using pattern matching, which is a clean approach.


96-98: LGTM! Runtime configurability added.

The setXmlConfig method allows dynamic configuration of XML namespaces, which is useful for runtime adjustments.

core/src/main/java/com/predic8/membrane/core/openapi/serviceproxy/APIProxy.java (3)

48-48: LGTM! APIProxy gains XML configuration support.

The implementation of XMLSupport enables XML namespace configuration for test expressions in API proxies.


86-91: LGTM! Proper XML config propagation.

The expression initialization correctly uses InterceptorAdapter(router, xmlConfig) and is properly guarded by a null/empty check on the test attribute.


244-256: LGTM! Consistent XML configuration implementation.

The XML configuration methods follow the established pattern across all interceptors.

core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (3)

51-51: LGTM! XML configuration support added to deprecated extractor.

While this class is deprecated, the XMLSupport implementation ensures backward compatibility for existing users who may need XML namespace support in their expressions.


59-61: LGTM! Correct XML config propagation.

The expression initialization properly uses InterceptorAdapter(router, xmlConfig) to enable XML namespace support.


101-114: LGTM! Well-documented XML configuration methods.

The implementation is consistent with other interceptors, with proper documentation explaining the purpose of XML configuration.

core/src/main/java/com/predic8/membrane/core/lang/ExchangeExpression.java (3)

17-19: LGTM!

The new imports support the InterceptorAdapter class and XMLSupport functionality introduced in this file.


53-68: Factory method signature updated to accept Interceptor.

The change from Router to Interceptor parameter enables XML namespace context propagation to GROOVY and XPATH expressions, aligning with the PR's objective. The added Javadoc appropriately guides callers to use InterceptorAdapter when no interceptor is available.

Note: A reviewer questioned whether the interceptor is becoming a "god-object" and suggested declaring namespaces globally (see rrayst's comment on line 61). While this is a valid architectural concern, the current implementation is functionally correct.


70-100: No issues found. Code is correct.

The router field in AbstractInterceptor is declared as protected, allowing InterceptorAdapter (a subclass) to safely access and assign to it. The pattern is consistent and will compile without issues.

core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (2)

46-72: LGTM!

The Namespace inner class provides a clean data holder for prefix-URI mappings with appropriate annotations for XML configuration parsing.


74-101: NamespaceContext implementation is correct once line 27 is fixed.

The NamespaceContextImpl correctly implements the javax.xml.namespace.NamespaceContext contract, returning appropriate defaults (NULL_NS_URI, null, or empty iterator) for unknown mappings. However, all methods will throw NPE until the namespaces field is initialized on line 27.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (1)

27-27: Initialize namespaces field to prevent NullPointerException.

The namespaces field remains uninitialized and will cause NPE in NamespaceContextImpl methods (lines 78, 87, 96) that call namespaces.stream() whenever setNamespace() is not called or is called with null.

Apply this diff to initialize the field:

-    private List<Namespace> namespaces;
+    private List<Namespace> namespaces = new ArrayList<>();
🧹 Nitpick comments (1)
core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (1)

46-72: Consider making fields private for better encapsulation.

The prefix and uri fields are public (lines 49-50), allowing direct access that bypasses the setters. While this may be intentional for framework compatibility, making them private would improve encapsulation and ensure all access goes through the annotated setters.

Apply this diff if stricter encapsulation is desired:

-        public String prefix;
-        public String uri;
+        private String prefix;
+        private String uri;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b7b720 and d05683e.

📒 Files selected for processing (2)
  • core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (2)
core/src/main/java/com/predic8/membrane/core/config/xml/XmlConfig.java (1)
  • MCElement (5-18)
core/src/main/java/com/predic8/membrane/core/interceptor/apikey/extractors/ApiKeyExpressionExtractor.java (1)
  • MCElement (50-115)
core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (2)
core/src/main/java/com/predic8/membrane/core/util/xml/parser/HardenedXmlParser.java (1)
  • HardenedXmlParser (30-99)
core/src/main/java/com/predic8/membrane/core/util/xml/XMLUtil.java (1)
  • XMLUtil (30-85)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (5)
core/src/main/java/com/predic8/membrane/core/config/xml/Namespaces.java (4)

30-32: LGTM!

The getter correctly exposes the NamespaceContext implementation for XPath expression evaluation.


34-40: Javadoc correction applied; verify null-safety.

The Javadoc has been correctly updated per previous feedback. However, the setter accepts and assigns a potentially null list without validation. Combined with the uninitialized field on line 27, ensure that calling code never passes null, or add defensive null handling.


42-44: LGTM!

The getter is correctly implemented. Returns null when namespaces are not configured, which may be the intended behavior for optional XML namespace configuration.


74-101: Implementation logic is correct but depends on null-safety fix.

The NamespaceContext implementation correctly follows the contract:

  • getNamespaceURI returns NULL_NS_URI for unmatched prefixes
  • getPrefix returns null for unmatched URIs
  • getPrefixes returns an iterator over all matching prefixes

However, lines 78, 87, and 96 will throw NPE if namespaces is null. This issue will be resolved once the critical initialization fix on line 27 is applied.

core/src/main/java/com/predic8/membrane/core/lang/xpath/XPathExchangeExpression.java (1)

89-91: Thanks for adding the namespace null guard.

This prevents the XPath namespace context setup from throwing when XmlConfig has no namespaces configured.

@predic8 predic8 merged commit 37749aa into master Nov 5, 2025
4 of 5 checks passed
@predic8 predic8 deleted the xml-namespace-declarations-for-xpath-expressions branch November 5, 2025 13:06
This was referenced Dec 15, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Jan 7, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jan 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Example Test: xml/namespaces

3 participants